define([], function () {
    var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;

    function AABB() {
        "use strict";
        this.minX = MAX_SAFE_INTEGER;
        this.maxX = -MAX_SAFE_INTEGER;
        this.minY = MAX_SAFE_INTEGER;
        this.maxY = -MAX_SAFE_INTEGER;
        this.minZ = MAX_SAFE_INTEGER;
        this.maxZ = -MAX_SAFE_INTEGER;
        this.inited = false;
    }

    AABB.prototype = {
        reset: function () {
            this.minX = MAX_SAFE_INTEGER;
            this.maxX = -MAX_SAFE_INTEGER;
            this.minY = MAX_SAFE_INTEGER;
            this.maxY = -MAX_SAFE_INTEGER;
            this.minZ = MAX_SAFE_INTEGER;
            this.maxZ = -MAX_SAFE_INTEGER;
            this.inited = false;
        },
        combine: function (p, y, z) {
            var type = typeof p;

            if (type === 'object') {
                this.combineXYZ(p.x, p.y, p.z);
            } else if (type === 'array') {
                this.combineXYZ(p[0], p[1], p[2]);
            } else if (type === 'number') {
                this.combineXYZ(p, y, z);
            }
        },
        combineXY: function (x, y) {
            if (y === undefined && x.length > 1) {
                y = x[1];
                x = x[0];
            }
            if (x < this.minX) this.minX = x;
            if (x > this.maxX) this.maxX = x;
            if (y < this.minY) this.minY = y;
            if (y > this.maxY) this.maxY = y;
            this.inited = true;
        },
        combineXYZ: function (x, y, z) {
            if (y === undefined && x.length > 1) {
                y = x[1];
                x = x[0];
            }
            if (x < this.minX) this.minX = x;
            if (x > this.maxX) this.maxX = x;
            if (y < this.minY) this.minY = y;
            if (y > this.maxY) this.maxY = y;
            if (z < this.minZ) this.minZ = z;
            if (z > this.maxZ) this.maxZ = z;
            this.inited = true;
        },
        combineXYs: function (xys) {
            var minX = this.minX;
            var maxX = this.maxX;
            var minY = this.minY;
            var maxY = this.maxY;
            xys.forEach(function (xy) {
                var x = xy[0];
                var y = xy[1];
                if (x < minX) minX = x;
                if (x > maxX) maxX = x;
                if (y < minY) minY = y;
                if (y > maxY) maxY = y;
            });
            this.minX = minX;
            this.maxX = maxX;
            this.minY = minY;
            this.maxY = maxY;
            this.inited = true;
        },
        pointOutside: function (x, y, z) {
            if (z !== undefined && z !== null) {
                if (z < this.minZ || z > this.maxZ) return true;
            }
            return (x < this.minX || x > this.maxX || y < this.minY || y > this.maxY);
        }
    };
    Object.defineProperties(AABB.prototype, {
        cenX: {
            get: function () {
                return (this.minX + this.maxX) / 2;
            }
        },
        cenY: {
            get: function () {
                return (this.minY + this.maxY) / 2;
            }
        },
        cenZ: {
            get: function () {
                return (this.minZ + this.maxZ) / 2;
            }
        },
        mx: {
            get: function () {
                return (this.minX + this.maxX) / 2;
            }
        },
        my: {
            get: function () {
                return (this.minY + this.maxY) / 2;
            }
        },
        mz: {
            get: function () {
                return (this.minZ + this.maxZ) / 2;
            }
        },
        dx: {
            get: function () {
                return (this.maxX - this.minX);
            }
        },
        dy: {
            get: function () {
                return (this.maxY - this.minY);
            }
        },
        dz: {
            get: function () {
                return (this.maxZ - this.minZ);
            }
        }
    });

    return AABB;
});